package com.dapangdong.testdemo.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * <p>
 *     RedisConfig配置
 *     实现了监听__keyevent@*__:expired
 * </p>
 *
 * @author : yhd
 * @program: gulimall
 * @since : 2023-06-12 17:54
 */
@RequiredArgsConstructor
@Configuration
public class RedisConfiguration {

    /**
     * Redis链接工厂
     */
    private final RedisConnectionFactory redisConnectionFactory;


    /**
     * 缓存操作组件RedisTemplate的自定义配置
     * @return 操作组件RedisTemplate
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(){
        //定义RedisTemplate实例
        RedisTemplate<String, Object> redisTemplate= new RedisTemplate<>();
        //设置Redis的链接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置key的序列化器
        //TODO：指定大Key序列化策略为String序列化，Value为JDK自带的序列化策略
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置value的序列化器,默认StringRedisSerializer
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());
        //TODO：指定hashKey序列化策略为String序列化-针对hash散列存储
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer());
        // 设置支持事务
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }

    @Bean
    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        //Json序列化设置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

        // 创建JavaTimeModule实例
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        // 创建DateTimeFormatter实例
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 注册LocalDateTime序列化器
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter));
        // 注册LocalDate序列化器
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
        // 创建SimpleModule实例
        SimpleModule dateModule = new SimpleModule();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 创建DateFormat实例
        // 注册Date序列化器
        dateModule.addSerializer(Date.class, new DateSerializer(false, dateFormat));

        ObjectMapper objectMapper = new ObjectMapper()
//                .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
//                .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)
                // 向ObjectMapper注册JavaTimeModule实例
                .registerModules(javaTimeModule,dateModule)
                // 关闭写入时间戳的选项
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }

    /**
     * 缓存操作组件StringRedisTemplate
     * @return 操作组件StringRedisTemplate
     */
    @Bean
    public StringRedisTemplate stringRedisTemplate(){
        //采用默认配置即可-后续有自定义配置时则在此处添加即可
        StringRedisTemplate stringRedisTemplate=new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
        return stringRedisTemplate;
    }


    //====================侦听Redis通道上的消息========================
    /**
     * 用于创建RedisMessageListenerContainer实例，以侦听Redis通道上的消息
     * 将RedisConnectionFactory注入到该方法中，并使用它来设置连接工厂
     * @param connectionFactory 将RedisConnectionFactory注入到该方法中，并使用它来设置连接工厂
     * @return RedisMessageListenerContainer实例
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(connectionFactory);
        return redisMessageListenerContainer;
    }

    /**
     * KeyExpirationEventMessageListener实现了对__keyevent@*__:expiredchannel的监听
     * 当KeyExpirationEventMessageListener收到Redis发布的过期Key的消息的时候，会发布RedisKeyExpiredEvent事件
     */
    @Bean
    public KeyExpirationEventMessageListener redisKeyExpirationListener(RedisMessageListenerContainer redisMessageListenerContainer) {
        return new KeyExpirationEventMessageListener(redisMessageListenerContainer);
    }

    //================================================================







}
